package com.fs.service;

import com.fs.entity.Price;
import com.fs.entity.Room;
import com.fs.repository.PriceRepository;
import com.fs.repository.RoomRepository;
import com.fs.service.bo.BoPageInfo;
import com.fs.service.bo.price.BoCreateRoomPriceParam;
import com.fs.service.bo.price.BoPrice;
import com.fs.service.bo.price.BoPriceWithRoom;
import com.fs.service.bo.price.BoQueryParam;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import javax.validation.Valid;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

@Service
@Transactional
@Validated
public class PriceService {
    private final PriceRepository priceDao;
    private final RoomRepository roomDao;

    public PriceService(PriceRepository priceDao, RoomRepository roomDao) {
        this.priceDao = priceDao;
        this.roomDao = roomDao;
    }

    public BoPrice createPrice(int roomID, float price, LocalTime start, LocalTime end) {
        Optional<Room> roomOptional = roomDao.findById(roomID);
        if (!roomOptional.isPresent()) {
            throw new NotFoundException("没有找到房间");
        }
        Price p = new Price();
        p.setPrice(price);
        p.setBeginTime(start);
        p.setEndTime(end);
        p.setRoom(roomOptional.get());
        priceDao.save(p);
        return new BoPrice(p);
    }

    public List<BoPrice> getPricesOfRoom(int roomID) {
        Room room = new Room();
        room.setId(roomID);
        List<Price> list = priceDao.findByRoom(room);
        return list.stream().map(BoPrice::new).collect(toList());
    }

    public BoPriceWithRoom createPrice(@Valid BoCreateRoomPriceParam roomPriceParam) {

        Room room = new Room();
        room.setId(roomPriceParam.getRoomId());

        Price price = new Price();
        price.setRoom(room);
        price.setPrice(roomPriceParam.getPrice());
        price.setBeginTime(roomPriceParam.getBeginTime());
        price.setEndTime(roomPriceParam.getEndTime());
        priceDao.save(price);
        return new BoPriceWithRoom(price);
    }

    public void deletePrice(Integer priceid){
        Optional<Price> optionalPrice = priceDao.findById(priceid);
        if (!optionalPrice.isPresent()) {
            throw new NotFoundException("没有找到对应的价格列表");
        }
        Price price = optionalPrice.get();
        price.setRoom(null);
        priceDao.deleteById(priceid);
    }

    public BoPageInfo<BoPriceWithRoom> query(@Valid BoQueryParam param,int pageNo, int pageSize){
        Specification<Price> spec = (Root<Price> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (param.getPrice() != null) {
                predicates.add(cb.equal(root.get("price"), param.getPrice()));
            }
            if (param.getBeginDateTime() != null) {
                predicates.add(cb.equal(root.get("beginTime"), param.getBeginDateTime()));
            }
            if (param.getEndDateTime() != null) {
                predicates.add(cb.equal(root.get("endTime"),param.getEndDateTime()));
            }
            if (param.getRoomId() != null){
                predicates.add(cb.equal(root.get("room") , param.getRoomId()));
            }
            int size = predicates.size();
            return query.where(predicates.toArray(new Predicate[size])).getRestriction();
        };

        if (pageNo > 0 && pageSize > 0) {
            Pageable pageable = PageRequest.of(pageNo,pageSize);
            Page<Price> page = priceDao.findAll(spec, pageable);
            List<BoPriceWithRoom> data = page.getContent().stream().map(BoPriceWithRoom::new).collect(toList());
            return new BoPageInfo<>(data, page.getTotalElements());
        } else {
            List<BoPriceWithRoom> list = priceDao.findAll(spec).stream().map(BoPriceWithRoom::new).collect(toList());
            return new BoPageInfo<>(list, null);
        }

    }

}

